---
title: 功能类优先
description: 在一组受约束的原始功能类的基础上构建复杂的组件。
---

import { Heading } from '@/components/Heading'
import { TipGood, TipBad } from '@/components/Tip'
import { CodeSample } from '@/components/CodeSample'

## <Heading hidden>概述</Heading>

<!-- Traditionally, whenever you need to style something on the web, you write CSS. -->
传统情况下，当您需要在网页上设置样式时，都需要编写 CSS。

<TipBad>
使用传统方式时，定制的设计需要定制的 CSS
</TipBad>

```html lightBlue
<template preview class="px-6 py-12">
  <div class="max-w-sm mx-auto p-6 flex items-center bg-white rounded-xl shadow-md space-x-4">
    <div class="flex-shrink-0">
      <svg class="h-12 w-12" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a"><stop stop-color="#2397B3" offset="0%"/><stop stop-color="#13577E" offset="100%"/></linearGradient><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="b"><stop stop-color="#73DFF2" offset="0%"/><stop stop-color="#47B1EB" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M28.872 22.096c.084.622.128 1.258.128 1.904 0 7.732-6.268 14-14 14-2.176 0-4.236-.496-6.073-1.382l-6.022 2.007c-1.564.521-3.051-.966-2.53-2.53l2.007-6.022A13.944 13.944 0 0 1 1 24c0-7.331 5.635-13.346 12.81-13.95A9.967 9.967 0 0 0 13 14c0 5.523 4.477 10 10 10a9.955 9.955 0 0 0 5.872-1.904z" fill="url(#a)" transform="translate(1 1)"/><path d="M35.618 20.073l2.007 6.022c.521 1.564-.966 3.051-2.53 2.53l-6.022-2.007A13.944 13.944 0 0 1 23 28c-7.732 0-14-6.268-14-14S15.268 0 23 0s14 6.268 14 14c0 2.176-.496 4.236-1.382 6.073z" fill="url(#b)" transform="translate(1 1)"/><path d="M18 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM24 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM30 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#FFF"/></g></svg>
    </div>
    <div>
      <div class="text-xl font-medium text-black">ChitChat</div>
      <p class="text-gray-500">You have a new message!</p>
    </div>
  </div>
</template>

<div class="chat-notification">
  <div class="chat-notification-logo-wrapper">
    <img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div class="chat-notification-content">
    <h4 class="chat-notification-title">ChitChat</h4>
    <p class="chat-notification-message">You have a new message!</p>
  </div>
</div>

<style>
  .chat-notification {
    display: flex;
    max-width: 24rem;
    margin: 0 auto;
    padding: 1.5rem;
    border-radius: 0.5rem;
    background-color: #fff;
    box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  }
  .chat-notification-logo-wrapper {
    flex-shrink: 0;
  }
  .chat-notification-logo {
    height: 3rem;
    width: 3rem;
  }
  .chat-notification-content {
    margin-left: 1.5rem;
    padding-top: 0.25rem;
  }
  .chat-notification-title {
    color: #1a202c;
    font-size: 1.25rem;
    line-height: 1.25;
  }
  .chat-notification-message {
    color: #718096;
    font-size: 1rem;
    line-height: 1.5;
  }
</style>
```

<!-- With Tailwind, you style elements by applying pre-existing classes directly in your HTML. -->
使用 Tailwind，您可以通过直接在 HTML 中应用预先存在的类来设置元素的样式。
<TipGood>
{/* Using utility classes to build custom designs without writing CSS */}
使用功能类构建自定义设计而无需编写 CSS
</TipGood>

```html lightBlue
<template preview class="px-6 py-12">
  <div class="max-w-sm mx-auto p-6 flex items-center bg-white rounded-xl shadow-md space-x-4">
    <div class="flex-shrink-0">
      <svg class="h-12 w-12" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a"><stop stop-color="#2397B3" offset="0%"/><stop stop-color="#13577E" offset="100%"/></linearGradient><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="b"><stop stop-color="#73DFF2" offset="0%"/><stop stop-color="#47B1EB" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M28.872 22.096c.084.622.128 1.258.128 1.904 0 7.732-6.268 14-14 14-2.176 0-4.236-.496-6.073-1.382l-6.022 2.007c-1.564.521-3.051-.966-2.53-2.53l2.007-6.022A13.944 13.944 0 0 1 1 24c0-7.331 5.635-13.346 12.81-13.95A9.967 9.967 0 0 0 13 14c0 5.523 4.477 10 10 10a9.955 9.955 0 0 0 5.872-1.904z" fill="url(#a)" transform="translate(1 1)"/><path d="M35.618 20.073l2.007 6.022c.521 1.564-.966 3.051-2.53 2.53l-6.022-2.007A13.944 13.944 0 0 1 23 28c-7.732 0-14-6.268-14-14S15.268 0 23 0s14 6.268 14 14c0 2.176-.496 4.236-1.382 6.073z" fill="url(#b)" transform="translate(1 1)"/><path d="M18 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM24 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM30 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#FFF"/></g></svg>
    </div>
    <div>
      <div class="text-xl font-medium text-black">ChitChat</div>
      <p class="text-gray-500">You have a new message!</p>
    </div>
  </div>
</template>

<div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4">
  <div class="flex-shrink-0">
    <img class="h-12 w-12" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div>
    <div class="text-xl font-medium text-black">ChitChat</div>
    <p class="text-gray-500">You have a new message!</p>
  </div>
</div>
```

在上面的示例中，我们使用了：

- 使用 Tailwind 的 [flexbox](/docs/display#flex) 和 [padding](/docs/padding) 功能类 (`flex`, `flex-shrink-0`, 和 `p-6`) 来控制整体的卡片布局
- 使用 [max-width](/docs/max-width) 和 [margin](/docs/margin) 功能类 (`max-w-sm` 和 `mx-auto`) 来设置卡片的宽度和水平居中
- 使用 [background color](/docs/background-color), [border radius](/docs/border-radius), 和 [box-shadow](/docs/box-shadow) 功能类 (`bg-white`, `rounded-xl`, 和 `shadow-md`) 设置卡片的外观样式
- 使用 [width](/docs/width) 和 [height](/docs/height) 功能类 (`w-12` and `h-12`) 来设置 logo 图片的大小
- 使用 [space-between](/docs/space) 功能类 (`space-x-4`) 来处理 logo 和文本之间的间距
- 使用 [font size](/docs/font-size)，[text color](/docs/text-color)，和 [font-weight](/docs/font-weight) 功能类 (`text-xl`，`text-black`，`font-medium` 等等) 给卡片文字设置样式

这种方法使我们无需编写一行自定义的 CSS 即可实现一个完全定制的组件设计。

我知道您在想："这太繁琐了，真是一团糟！" 您是对的，这有点丑陋。实际上，当您第一次看到它时，几乎不可能认为这是一个好主意--您必须实际尝试一下。

但是，一旦您以这种方式实际构建了一些东西，您就会很快注意到一些真正重要的优点：

- **您没有为了给类命名而浪费精力**。 不需要仅仅为了设置一些样式而额外添加一些像 `sidebar-inner-wrapper` 这样愚蠢的类名，不必再为了一个 flex 容器的完美抽象命名而倍受折磨。
- **您的 CSS 停止增长**。 使用传统方法，每次添加新功能时 CSS 文件都会变大。使用功能类，所有内容都是可重用的，因此您几乎不需要编写新的CSS。
- **更改会更安全**。 CSS 是全局性的，您永远不知道当您进行更改时会破坏掉什么。您 HTML 中的类是本地的，因此您可以更改它们而不必担心其他问题。

当您意识到在 HTML 中使用预定义的功能类是多么的富有成效时，以任何其他方式工作都感觉像是折磨。

---

## 为什么不使用内联样式？

对这种方式的一个普遍反应是, "这不就是内联样式吗？" 在某些方面是 — 您是将样式直接应用于元素，而不是为元素分配一个类，然后在这个类中设置样式。

但是使用功能类比内联样式具有一些重要的优点：

- **基于约束的设计**. 使用内联样式, 每个值都是一个魔术数字。 使用功能类, 您是从预定义的[设计系统](/docs/theme)中选择样式，这使得构建统一的UI变得更加容易。
- **响应式的设计**. 在内联样式中您不能使用媒体查询, 但您可以使用 Tailwind 的[响应式功能类](/docs/responsive-design)非常容易的构建完全响应式的界面。
- **Hover, focus, 以及其它状态**. 内联样式无法设置 hover 或者 focus 这样的状态, 但 Tailwind 的[状态变体](/docs/hover-focus-and-other-states)使用功能类可以非常容易的为这些状态设置样式。

该组件完全响应，并包括具有 hover 和 focus 样式的按钮，完全由功能类构建：

```html purple
<template preview class="px-6 py-12">
  <div class="py-8 px-8 max-w-sm mx-auto bg-white rounded-xl shadow-md sm:flex sm:items-center space-y-2 sm:space-y-0 sm:space-x-6 sm:py-4">
    <img class="block mx-auto sm:mx-0 sm:flex-shrink-0 h-24 rounded-full" src="/img/erin-lindford.jpg" alt="Woman's Face">
    <div class="text-center sm:text-left space-y-2">
      <div class="space-y-0.5">
        <p class="text-lg text-black font-semibold">
          Erin Lindford
        </p>
        <p class="text-gray-500 font-medium">
          Product Engineer
        </p>
      </div>
      <button class="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2">Message</button>
    </div>
  </div>
</template>

<div class="py-8 px-8 max-w-sm mx-auto bg-white rounded-xl shadow-md space-y-2 **sm:py-4 sm:flex sm:items-center sm:space-y-0 sm:space-x-6**">
  <img class="block mx-auto h-24 rounded-full **sm:mx-0 sm:flex-shrink-0**" src="/img/erin-lindford.jpg" alt="Woman's Face">
  <div class="text-center space-y-2 **sm:text-left**">
    <div class="space-y-0.5">
      <p class="text-lg text-black font-semibold">
        Erin Lindford
      </p>
      <p class="text-gray-500 font-medium">
        Product Engineer
      </p>
    </div>
    <button class="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 **hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2**">Message</button>
  </div>
</div>
```

---

## 可维护性问题

在使用功能优先的方式时，最大的可维护性问题是管理通用的可重复使用的功能类组合。

通过[提取组件](/docs/extracting-components)（通常做为模板片断或者组件），可以轻松解决此问题。

```html
<!-- PrimaryButton.vue -->
<template>
  <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
    <slot/>
  </button>
</template>
```

<!-- You can also use Tailwind's `@apply` feature to create CSS abstractions around common utility patterns. -->
您也可以使用 Tailwind 的 `@apply` 功能创建抽象的 CSS 类。

```html emerald
<template preview>
  <div class="text-center">
    <button type="button" class="py-2 px-4 bg-emerald-500 text-white font-semibold rounded-lg shadow-md hover:bg-emerald-700 focus:outline-none" tabindex="-1">
      Click me
    </button>
  </div>
</template>

<!-- Using utilities -->
<button class="py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-green-500 hover:bg-green-700">
  Click me
</button>

<!-- Extracting classes using @apply -->
<button class="**btn btn-green**">
  Button
</button>

<style>
  **.btn** {
    @apply py-2 px-4 font-semibold rounded-lg shadow-md;
  }
  **.btn-green** {
    @apply text-white bg-green-500 hover:bg-green-700;
  }
</style>
```

除此之外，维护功能优先的 CSS 项目比维护大型 CSS 代码库要容易得多，因为 HTML 比 CSS 维护容易得多。诸如 GitHub，Heroku，Kickstarter，Twitch，Segment 等大型公司都在使用这种方法，且取得巨大成功。

如果您想了解其他人使用此方法的经验，请查看以下资源：

- [By The Numbers: A Year and a Half with Atomic CSS](https://medium.com/@johnpolacek/by-the-numbers-a-year-and-half-with-atomic-css-39d75b1263b4) by John Polacek
- [Building a Scalable CSS Architecture](https://blog.algolia.com/redesigning-our-docs-part-4-building-a-scalable-css-architecture/) by Sarah Dayan of Algolia
- [Diana Mounter on using utility classes at GitHub](http://www.fullstackradio.com/75), a podcast interview

查看 [John Polacek](https://twitter.com/johnpolacek) 策划的 [The Case for Atomic/Utility-First CSS](https://johnpolacek.github.io/the-case-for-atomic-css/) 了解更多信息。
